home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / program / ny_src.zip / INTERBBS.CPP < prev    next >
C/C++ Source or Header  |  1996-04-05  |  47KB  |  1,756 lines

  1. #include <assert.h>
  2. #include <ctype.h>
  3. #include <string.h>
  4. #include <dir.h>
  5. #include <time.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <io.h>
  9. #include <dos.h>
  10. #include <fcntl.h>
  11. #include <sys\stat.h>
  12.  
  13. //typedef unsigned int WORD;
  14. //typedef unsigned long DWORD;
  15.  
  16. #include "\tc\ny2008.h"
  17. //#include "\ibbs\interbbs.h"
  18. extern unsigned _stklen;
  19.  
  20.  
  21. char aszShortMonthName[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  22.                  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  23.  
  24. tBool DirExists(const char *pszDirName)
  25.    {
  26.    char szDirFileName[PATH_CHARS + 1];
  27.    struct ffblk DirEntry;
  28.  
  29. //   if(pszDirName==NULL) return(FALSE);
  30. //   if(strlen(pszDirName)>PATH_CHARS) return(FALSE);
  31.    assert(pszDirName != NULL);
  32.    assert(strlen(pszDirName) <= PATH_CHARS);
  33.  
  34.    strcpy(szDirFileName, pszDirName);
  35.  
  36.    /* Remove any trailing backslash from directory name */
  37.    if(szDirFileName[strlen(szDirFileName) - 1] == '\\')
  38.       {
  39.       szDirFileName[strlen(szDirFileName) - 1] = '\0';
  40.       }
  41.  
  42.    /* Return true iff file exists and it is a directory */
  43.    return(findfirst(szDirFileName, &DirEntry, FA_ARCH|FA_DIREC) == 0 &&
  44.          (DirEntry.ff_attrib & FA_DIREC));
  45.    }
  46.  
  47.  
  48. void MakeFilename(const char *pszPath, const char *pszFilename, char *pszOut)
  49.    {
  50.    /* Validate parameters in debug mode */
  51.    assert(pszPath != NULL);
  52.    assert(pszFilename != NULL);
  53.    assert(pszOut != NULL);
  54.    assert(pszPath != pszOut);
  55.    assert(pszFilename != pszOut);
  56.  
  57.    /* Copy path to output filename */
  58.    strcpy(pszOut, pszPath);
  59.  
  60.    /* Ensure there is a trailing backslash */
  61.    if(pszOut[strlen(pszOut) - 1] != '\\')
  62.       {
  63.       strcat(pszOut, "\\");
  64.       }
  65.  
  66.    /* Append base filename */
  67.    strcat(pszOut, pszFilename);
  68.    }
  69.  
  70.  
  71. tIBResult IBSendAll(tIBInfo *pInfo, void *pBuffer, int nBufferSize)
  72.    {
  73.    tIBResult ToReturn;
  74.    int iCurrentSystem;
  75.  
  76.    if(pBuffer == NULL) return(eBadParameter);
  77.  
  78.    /* Validate information structure */
  79.    ToReturn = ValidateInfoStruct(pInfo);
  80.    if(ToReturn != eSuccess) return(ToReturn);
  81.  
  82.    if(pInfo->paOtherSystem == NULL && pInfo->nTotalSystems != 0)
  83.       {
  84.       return(eBadParameter);
  85.       }
  86.  
  87.    /* Loop for each system in other systems array */
  88.    for(iCurrentSystem = 0; iCurrentSystem < pInfo->nTotalSystems;
  89.     ++iCurrentSystem)
  90.       {
  91.       /* Send information to that system */
  92.       if(strcmp(pInfo->paOtherSystem[iCurrentSystem].szAddress,pInfo->szThisNodeAddress)!=0)
  93.     {
  94.     ToReturn = IBSend(pInfo, pInfo->paOtherSystem[iCurrentSystem].szAddress,
  95.             pBuffer, nBufferSize);
  96.     if(ToReturn != eSuccess) return(ToReturn);
  97.     }
  98.       }
  99.  
  100.    return(eSuccess);
  101.    }
  102.  
  103.  
  104. tIBResult IBSend(tIBInfo *pInfo, char *pszDestNode, void *pBuffer,
  105.          int nBufferSize)
  106.    {
  107.    tIBResult ToReturn;
  108.    tMessageHeader MessageHeader;
  109.    time_t lnSecondsSince1970;
  110.    struct tm *pTimeInfo;
  111.    char szTOPT[13];
  112.    char szFMPT[13];
  113.    char szINTL[43];
  114.    char szMSGID[42];
  115.    int nKludgeSize;
  116.    int nTextSize;
  117.    char *pszMessageText;
  118.    tFidoNode DestNode;
  119.    tFidoNode OrigNode;
  120.  
  121.    if(pszDestNode == NULL) return(eBadParameter);
  122.    if(pBuffer == NULL) return(eBadParameter);
  123.  
  124.    /* Validate information structure */
  125.    ToReturn = ValidateInfoStruct(pInfo);
  126.    if(ToReturn != eSuccess) return(ToReturn);
  127.  
  128.    /* Get destination node address from string */
  129.    ConvertStringToAddress(&DestNode, pszDestNode);
  130.  
  131.    /* Get origin address from string */
  132.    ConvertStringToAddress(&OrigNode, pInfo->szThisNodeAddress);
  133.  
  134.    /* Construct message header */
  135.    /* Construct to, from and subject information */
  136.    strcpy(MessageHeader.szFromUserName, pInfo->szProgName);
  137.    strcpy(MessageHeader.szToUserName, "@NY");
  138.    strcat(MessageHeader.szToUserName, pszDestNode);
  139.    strcpy(MessageHeader.szSubject, MESSAGE_SUBJECT);
  140.  
  141.    /* Construct date and time information */
  142.    lnSecondsSince1970 = time(NULL);
  143.    pTimeInfo = localtime(&lnSecondsSince1970);
  144.    sprintf(MessageHeader.szDateTime, "%02.2d %s %02.2d  %02.2d:%02.2d:%02.2d",
  145.            pTimeInfo->tm_mday,
  146.        aszShortMonthName[pTimeInfo->tm_mon],
  147.        pTimeInfo->tm_year,
  148.            pTimeInfo->tm_hour,
  149.            pTimeInfo->tm_min,
  150.            pTimeInfo->tm_sec);
  151.  
  152.    /* Construct misc. information */
  153.    MessageHeader.wTimesRead = 0;
  154.    MessageHeader.wCost = 0;
  155.    MessageHeader.wReplyTo = 0;
  156.    MessageHeader.wNextReply = 0;
  157.  
  158.    /* Construct destination address */
  159.    MessageHeader.wDestZone = DestNode.wZone;
  160.    MessageHeader.wDestNet = DestNode.wNet;
  161.    MessageHeader.wDestNode = DestNode.wNode;
  162.    MessageHeader.wDestPoint = DestNode.wPoint;
  163.  
  164.    /* Construct origin address */
  165.    MessageHeader.wOrigZone = OrigNode.wZone;
  166.    MessageHeader.wOrigNet = OrigNode.wNet;
  167.    MessageHeader.wOrigNode = OrigNode.wNode;
  168.    MessageHeader.wOrigPoint = OrigNode.wPoint;
  169.  
  170.    /* Construct message attributes */
  171.    MessageHeader.wAttribute = ATTRIB_PRIVATE | ATTRIB_LOCAL;
  172.    if(pInfo->bCrash) MessageHeader.wAttribute |= ATTRIB_CRASH;
  173.    if(pInfo->bHold) MessageHeader.wAttribute |= ATTRIB_HOLD;
  174.    if(pInfo->bEraseOnSend) MessageHeader.wAttribute |= ATTRIB_KILL_SENT;
  175.  
  176.    /* Create message control (kludge) lines */
  177.    /* Create TOPT kludge line if destination point is non-zero */
  178.    if(DestNode.wPoint != 0)
  179.       {
  180.      sprintf(szTOPT, "\1TOPT %u\r", DestNode.wPoint);
  181.       }
  182.    else
  183.       {
  184.       strcpy(szTOPT, "");
  185.       }
  186.  
  187.    /* Create FMPT kludge line if origin point is non-zero */
  188.    if(OrigNode.wPoint != 0)
  189.       {
  190.       sprintf(szFMPT, "\1FMPT %u\r", OrigNode.wPoint);
  191.       }
  192.    else
  193.       {
  194.       strcpy(szFMPT, "");
  195.       }
  196.  
  197.    /* Create INTL kludge line if origin and destination zone addresses differ */
  198.    if(DestNode.wZone != OrigNode.wZone)
  199.       {
  200.       sprintf(szINTL, "\1INTL %u:%u/%u %u:%u/%u\r",
  201.           DestNode.wZone,
  202.           DestNode.wNet,
  203.               DestNode.wNode,
  204.           OrigNode.wZone,
  205.               OrigNode.wNet,
  206.           OrigNode.wNode);
  207.       }
  208.    else
  209.       {
  210.       strcpy(szINTL, "");
  211.       }
  212.  
  213.    /* Create MSGID kludge line, including point if non-zero */
  214.    if(OrigNode.wPoint != 0)
  215.       {
  216.       sprintf(szMSGID, "\1MSGID: %u:%u/%u.%u %lx\r",
  217.           OrigNode.wZone,
  218.               OrigNode.wNet,
  219.           OrigNode.wNode,
  220.               OrigNode.wPoint,
  221.               GetNextMSGID());
  222.       }
  223.    else
  224.       {
  225.       sprintf(szMSGID, "\1MSGID: %u:%u/%u %lx\r",
  226.           OrigNode.wZone,
  227.               OrigNode.wNet,
  228.               OrigNode.wNode,
  229.               GetNextMSGID());
  230.       }
  231.  
  232.    /* Determine total size of kludge lines */
  233.    nKludgeSize = strlen(szTOPT)
  234.                 + strlen(szFMPT)
  235.                 + strlen(szINTL)
  236.         + strlen(szMSGID)
  237.                 + strlen(MESSAGE_PID);
  238.  
  239.    /* Determine total size of message text */
  240.    nTextSize = GetMaximumEncodedLength(nBufferSize)
  241.               + strlen(MESSAGE_HEADER)
  242.               + nKludgeSize
  243.           + strlen(MESSAGE_FOOTER)
  244.               + 1;
  245.  
  246.    /* Attempt to allocate space for message text */
  247.    if((pszMessageText = (char *)malloc(nTextSize)) == NULL)
  248.       {
  249.       return(eNoMemory);
  250.       }
  251.  
  252.    /* Construct message text */
  253.    strcpy(pszMessageText, szTOPT);
  254.    strcat(pszMessageText, szFMPT);
  255.    strcat(pszMessageText, szINTL);
  256.    strcat(pszMessageText, szMSGID);
  257.    strcat(pszMessageText, MESSAGE_PID);
  258.    strcat(pszMessageText, MESSAGE_HEADER);
  259.    EncodeBuffer(pszMessageText + strlen(pszMessageText), pBuffer, nBufferSize);
  260.    strcat(pszMessageText, MESSAGE_FOOTER);
  261.  
  262.    /* Attempt to send the message */
  263.    if(CreateMessage(pInfo->szNetmailDir, &MessageHeader, pszMessageText))
  264.       {
  265.       ToReturn = eSuccess;
  266.       }
  267.    else
  268.       {
  269.       ToReturn = eGeneralFailure;
  270.       }
  271.  
  272.    /* Deallocate message text buffer */
  273.    free(pszMessageText);
  274.  
  275.    /* Return appropriate value */
  276.    return(ToReturn);
  277.    }
  278.  
  279. tIBResult IBSendMail(tIBInfo *pInfo, ibbs_mail_type *ibmail)
  280.    {
  281.    tIBResult ToReturn;
  282.    tMessageHeader MessageHeader;
  283.    time_t lnSecondsSince1970;
  284.    struct tm *pTimeInfo;
  285.    char szTOPT[13];
  286.    char szFMPT[13];
  287.    char szINTL[43];
  288.    char szMSGID[42];
  289.    int nKludgeSize;
  290.    int nTextSize;
  291.    char *pszMessageText;
  292.    tFidoNode DestNode;
  293.    tFidoNode OrigNode;
  294.  
  295.    if(ibmail->node_r == NULL) return(eBadParameter);
  296.    if(ibmail == NULL) return(eBadParameter);
  297.  
  298.    /* Validate information structure */
  299.    ToReturn = ValidateInfoStruct(pInfo);
  300.    if(ToReturn != eSuccess) return(ToReturn);
  301.  
  302.    /* Get destination node address from string */
  303.    ConvertStringToAddress(&DestNode, ibmail->node_r);
  304.  
  305.    /* Get origin address from string */
  306.    ConvertStringToAddress(&OrigNode, pInfo->szThisNodeAddress);
  307.  
  308.  
  309.    /* Construct message header */
  310.    /* Construct to, from and subject information */
  311.    strcpy(MessageHeader.szFromUserName, pInfo->szProgName);
  312.    strcpy(MessageHeader.szToUserName, "@NY");
  313.    strcat(MessageHeader.szToUserName, ibmail->node_r);
  314.    strcpy(MessageHeader.szSubject, MESSAGE_SUBJECT);
  315.  
  316.  
  317.    /* Construct date and time information */
  318.    lnSecondsSince1970 = time(NULL);
  319.    pTimeInfo = localtime(&lnSecondsSince1970);
  320.    sprintf(MessageHeader.szDateTime, "%02.2d %s %02.2d  %02.2d:%02.2d:%02.2d",
  321.        pTimeInfo->tm_mday,
  322.        aszShortMonthName[pTimeInfo->tm_mon],
  323.        pTimeInfo->tm_year,
  324.        pTimeInfo->tm_hour,
  325.        pTimeInfo->tm_min,
  326.        pTimeInfo->tm_sec);
  327.  
  328.    /* Construct misc. information */
  329.    MessageHeader.wTimesRead = 0;
  330.    MessageHeader.wCost = 0;
  331.    MessageHeader.wReplyTo = 0;
  332.    MessageHeader.wNextReply = 0;
  333.  
  334.    /* Construct destination address */
  335.    MessageHeader.wDestZone = DestNode.wZone;
  336.    MessageHeader.wDestNet = DestNode.wNet;
  337.    MessageHeader.wDestNode = DestNode.wNode;
  338.    MessageHeader.wDestPoint = DestNode.wPoint;
  339.  
  340.    /* Construct origin address */
  341.    MessageHeader.wOrigZone = OrigNode.wZone;
  342.    MessageHeader.wOrigNet = OrigNode.wNet;
  343.    MessageHeader.wOrigNode = OrigNode.wNode;
  344.    MessageHeader.wOrigPoint = OrigNode.wPoint;
  345.  
  346.    /* Construct message attributes */
  347.    MessageHeader.wAttribute = ATTRIB_PRIVATE | ATTRIB_LOCAL;
  348.    if(pInfo->bCrash) MessageHeader.wAttribute |= ATTRIB_CRASH;
  349.    if(pInfo->bHold) MessageHeader.wAttribute |= ATTRIB_HOLD;
  350.    if(pInfo->bEraseOnSend) MessageHeader.wAttribute |= ATTRIB_KILL_SENT;
  351.  
  352.  
  353.    /* Create message control (kludge) lines */
  354.    /* Create TOPT kludge line if destination point is non-zero */
  355.    if(DestNode.wPoint != 0)
  356.       {
  357.      sprintf(szTOPT, "\1TOPT %u\r", DestNode.wPoint);
  358.       }
  359.    else
  360.       {
  361.       strcpy(szTOPT, "");
  362.       }
  363.  
  364.    /* Create FMPT kludge line if origin point is non-zero */
  365.    if(OrigNode.wPoint != 0)
  366.       {
  367.       sprintf(szFMPT, "\1FMPT %u\r", OrigNode.wPoint);
  368.       }
  369.    else
  370.       {
  371.       strcpy(szFMPT, "");
  372.       }
  373.  
  374.    /* Create INTL kludge line if origin and destination zone addresses differ */
  375.    if(DestNode.wZone != OrigNode.wZone)
  376.       {
  377.       sprintf(szINTL, "\1INTL %u:%u/%u %u:%u/%u\r",
  378.           DestNode.wZone,
  379.           DestNode.wNet,
  380.           DestNode.wNode,
  381.           OrigNode.wZone,
  382.           OrigNode.wNet,
  383.           OrigNode.wNode);
  384.       }
  385.    else
  386.       {
  387.       strcpy(szINTL, "");
  388.       }
  389.  
  390.    /* Create MSGID kludge line, including point if non-zero */
  391.    if(OrigNode.wPoint != 0)
  392.       {
  393.       sprintf(szMSGID, "\1MSGID: %u:%u/%u.%u %lx\r",
  394.           OrigNode.wZone,
  395.           OrigNode.wNet,
  396.           OrigNode.wNode,
  397.           OrigNode.wPoint,
  398.           GetNextMSGID());
  399.       }
  400.    else
  401.       {
  402.       sprintf(szMSGID, "\1MSGID: %u:%u/%u %lx\r",
  403.           OrigNode.wZone,
  404.           OrigNode.wNet,
  405.           OrigNode.wNode,
  406.           GetNextMSGID());
  407.       }
  408.  
  409.    /* Determine total size of kludge lines */
  410.    nKludgeSize = strlen(szTOPT)
  411.         + strlen(szFMPT)
  412.         + strlen(szINTL)
  413.         + strlen(szMSGID)
  414.         + strlen(MESSAGE_PID);
  415.  
  416.  
  417.    /* Determine total size of message text */
  418.    nTextSize = sizeof(ibbs_mail_type) * 2 + 4 * 20 + 1
  419.           + strlen(MESSAGE_HEADER)
  420.           + nKludgeSize
  421.           + strlen(MESSAGE_FOOTER)
  422.           + 1;
  423.  
  424.  
  425.    /* Attempt to allocate space for message text */
  426.    if((pszMessageText = (char *)malloc(nTextSize)) == NULL)
  427.       {
  428.       return(eNoMemory);
  429.       }
  430.  
  431.    /* Construct message text */
  432.    strcpy(pszMessageText, szTOPT);
  433.    strcat(pszMessageText, szFMPT);
  434.    strcat(pszMessageText, szINTL);
  435.    strcat(pszMessageText, szMSGID);
  436.    strcat(pszMessageText, MESSAGE_PID);
  437.    strcat(pszMessageText, MESSAGE_HEADER);
  438.  
  439.  
  440.    EncodeMail(pszMessageText + strlen(pszMessageText),ibmail);
  441. //   EncodeBuffer(pszMessageText + strlen(pszMessageText), pBuffer, nBufferSize);
  442.    strcat(pszMessageText, MESSAGE_FOOTER);
  443.  
  444.  
  445.    /* Attempt to send the message */
  446.    if(CreateMessage(pInfo->szNetmailDir, &MessageHeader, pszMessageText))
  447.       {
  448.       ToReturn = eSuccess;
  449.       }
  450.    else
  451.       {
  452.       ToReturn = eGeneralFailure;
  453.       }
  454.  
  455.  
  456.    /* Deallocate message text buffer */
  457.    free(pszMessageText);
  458.  
  459.  
  460.    /* Return appropriate value */
  461.    return(ToReturn);
  462.    }
  463.  
  464.  
  465.  
  466. int GetMaximumEncodedLength(int nUnEncodedLength)
  467.    {
  468.    int nEncodedLength;
  469.  
  470.    /* The current encoding algorithm uses two characters to represent   */
  471.    /* each byte of data, plus 1 byte per MAX_LINE_LENGTH characters for */
  472.    /* the carriage return character.                                    */
  473.  
  474.    nEncodedLength = nUnEncodedLength * 2;
  475.  
  476.    return(nEncodedLength + (nEncodedLength / MAX_LINE_LENGTH - 1) + 1);
  477.    }
  478.  
  479.  
  480. void EncodeBuffer(char *pszDest, const void *pBuffer, int nBufferSize)
  481.    {
  482.    int iSourceLocation;
  483.    int nOutputChars = 0;
  484.    char *pcDest = pszDest;
  485.    const char *pcSource = (char *)pBuffer;
  486.  
  487.    /* Loop for each byte of the source buffer */
  488.    for(iSourceLocation = 0; iSourceLocation < nBufferSize; ++iSourceLocation)
  489.       {
  490.       /* First character contains bits 0 - 5, with 01 in upper two bits */
  491.       *pcDest++ = (*pcSource & 0x3f) | 0x40;
  492.       /* Second character contains bits 6 & 7 in positions 4 & 5. Upper */
  493.       /* two bits are 01, and all remaining bits are 0. */
  494.       *pcDest++ = ((*pcSource & 0xc0) >> 2) | 0x40;
  495.  
  496.       /* Output carriage return when needed */
  497.       if((nOutputChars += 2) >= MAX_LINE_LENGTH - 1)
  498.          {
  499.      nOutputChars = 0;
  500.      *pcDest++ = '\r';
  501.      }
  502.  
  503.       /* Increment source pointer */
  504.       ++pcSource;
  505.       }
  506.  
  507.    /* Add one last carriage return, regardless of what has come before */
  508.    *pcDest++ = '\r';
  509.  
  510.    /* Terminate output string */
  511.    *pcDest++ = '\0';
  512.    }
  513.  
  514. void EncodeMail(char *pszDest,ibbs_mail_type *ibmail)
  515. {
  516.    char *pcDest = pszDest;
  517.    int x,l,ln;
  518.  
  519.    l=strlen(ibmail->sender);
  520.    for(x=0;x<l;x++) {
  521.      sprintf(pcDest,"%X",(int)ibmail->sender[x]);
  522.      pcDest+=2;
  523.    }
  524.    *pcDest='\n';
  525.    pcDest++;
  526.  
  527.    l=strlen(ibmail->senderI);
  528.    for(x=0;x<l;x++) {
  529.      sprintf(pcDest,"%X",(int)ibmail->senderI[x]);
  530.      pcDest+=2;
  531.    }
  532.    *pcDest='\n';
  533.    pcDest++;
  534.  
  535.    sprintf(pcDest,"%X",(int)ibmail->sender_sex);
  536.    pcDest++;
  537.  
  538.    *pcDest='\n';
  539.    pcDest++;
  540.  
  541.    l=strlen(ibmail->node_s);
  542.    for(x=0;x<l;x++) {
  543.      sprintf(pcDest,"%X",(int)ibmail->node_s[x]);
  544.      pcDest+=2;
  545.    }
  546.    *pcDest='\n';
  547.    pcDest++;
  548.  
  549.    l=strlen(ibmail->node_r);
  550.    for(x=0;x<l;x++) {
  551.      sprintf(pcDest,"%X",(int)ibmail->node_r[x]);
  552.      pcDest+=2;
  553.    }
  554.    *pcDest='\n';
  555.    pcDest++;
  556.  
  557.    l=strlen(ibmail->recver);
  558.    for(x=0;x<l;x++) {
  559.      sprintf(pcDest,"%X",(int)ibmail->recver[x]);
  560.      pcDest+=2;
  561.    }
  562.    *pcDest='\n';
  563.    pcDest++;
  564.  
  565.    l=strlen(ibmail->recverI);
  566.    for(x=0;x<l;x++) {
  567.      sprintf(pcDest,"%X",(int)ibmail->recverI[x]);
  568.      pcDest+=2;
  569.    }
  570.    *pcDest='\n';
  571.    pcDest++;
  572.  
  573.    sprintf(pcDest,"%X",(int)ibmail->quote_length);
  574.    pcDest++;
  575.  
  576.    *pcDest='\n';
  577.    pcDest++;
  578.  
  579.    sprintf(pcDest,"%X",(int)ibmail->length);
  580.    pcDest++;
  581.  
  582.    *pcDest='\n';
  583.    pcDest++;
  584.  
  585.    sprintf(pcDest,"%X",(int)ibmail->flirt);
  586.    pcDest++;
  587.  
  588.    *pcDest='\n';
  589.    pcDest++;
  590.  
  591.  
  592.    sprintf(pcDest,"%X",(int)ibmail->ill);
  593.    pcDest++;
  594.  
  595.    *pcDest='\n';
  596.    pcDest++;
  597.  
  598.    sprintf(pcDest,"%X",(int)ibmail->inf);
  599.    pcDest++;
  600.  
  601.    *pcDest='\n';
  602.    pcDest++;
  603.  
  604.    for(ln=0;ln<(ibmail->length + ibmail->quote_length) && ln<20;ln++) {
  605.      l=strlen(ibmail->lines[ln]);
  606.      for(x=0;x<l && x<20 ;x++) {
  607.        sprintf(pcDest,"%X",(int)ibmail->lines[ln][x]);
  608.        pcDest+=2;
  609.      }
  610.  
  611.      *pcDest='\n';
  612.      pcDest++;
  613.  
  614.      if(l<=20) {
  615.        *pcDest='0';
  616.        pcDest++;
  617.        *pcDest='0';
  618.        pcDest++;
  619.      }
  620.  
  621.      for(x=20;x<l && x<40;x++) {
  622.        sprintf(pcDest,"%X",(int)ibmail->lines[ln][x]);
  623.        pcDest+=2;
  624.      }
  625.      *pcDest='\n';
  626.      pcDest++;
  627.  
  628.      if(l<=40) {
  629.        *pcDest='0';
  630.        pcDest++;
  631.        *pcDest='0';
  632.        pcDest++;
  633.      }
  634.  
  635.      for(x=40;x<l && x<60;x++) {
  636.        sprintf(pcDest,"%X",(int)ibmail->lines[ln][x]);
  637.        pcDest+=2;
  638.      }
  639.  
  640.      *pcDest='\n';
  641.      pcDest++;
  642.  
  643.  
  644.      if(l<=60) {
  645.        *pcDest='0';
  646.        pcDest++;
  647.        *pcDest='0';
  648.        pcDest++;
  649.      }
  650.      for(x=60;x<l;x++) {
  651.        sprintf(pcDest,"%X",(int)ibmail->lines[ln][x]);
  652.        pcDest+=2;
  653.      }
  654.      *pcDest='\n';
  655.      pcDest++;
  656.    }
  657.    *pcDest = '\0';
  658. }
  659.  
  660.  
  661. void DecodeBuffer(const char *pszSource, void *pDestBuffer, int nBufferSize)
  662.    {
  663.    const char *pcSource = pszSource;
  664.    char *pcDest = (char *)pDestBuffer;
  665.    int iDestLocation;
  666.    tBool bFirstOfByte = TRUE;
  667.  
  668.    /* Search for beginning of buffer delimiter char, returning if not found */
  669.    while(*pcSource && *pcSource != DELIMITER_CHAR) ++pcSource;
  670.    if(!*pcSource) return;
  671.  
  672.    /* Move pointer to first char after delimiter char */
  673.    ++pcSource;
  674.  
  675.    /* Loop until destination buffer is full, delimiter char is encountered, */
  676.    /* or end of source buffer is encountered */
  677.    iDestLocation = 0;
  678.    while(iDestLocation < nBufferSize && *pcSource
  679.     && *pcSource != DELIMITER_CHAR)
  680.       {
  681.       /* If this is a valid data character */
  682.       if(*pcSource >= 0x40 && *pcSource <= 0x7e)
  683.      {
  684.      /* If this is first character of byte */
  685.      if(bFirstOfByte)
  686.         {
  687.             *pcDest = *pcSource & 0x3f;
  688.  
  689.         /* Toggle bFirstOfByte */
  690.             bFirstOfByte = FALSE;
  691.         }
  692.          else /* if(!bFirstOfByte) */
  693.             {
  694.             *pcDest |= (*pcSource & 0x30) << 2;
  695.  
  696.         /* Increment destination */
  697.         ++iDestLocation;
  698.         ++pcDest;
  699.  
  700.         /* Toggle bFirstOfByte */
  701.         bFirstOfByte = TRUE;
  702.         }
  703.      }
  704.  
  705.       /* Increment source byte pointer */
  706.       ++pcSource;
  707.       }
  708.    }
  709.  
  710. void DecodeMail(const char *pszSource, ibbs_mail_type *ibmail)
  711. {
  712.    const char *pcSource = pszSource;
  713.    int x,ln,t;
  714.    char tmp[5];
  715.  
  716.    tmp[2]=0;
  717.    x=0;
  718.  
  719.    while(*pcSource && *pcSource != DELIMITER_CHAR) ++pcSource;
  720.    if(!*pcSource) return;
  721.  
  722.    pcSource++;
  723.  
  724.    while(*pcSource<=' ')
  725.      pcSource++;
  726.  
  727.    while(*pcSource>' ') {
  728.      tmp[0]=*pcSource;
  729.      tmp[1]=*(pcSource+1);
  730.      sscanf(tmp,"%X",&t);
  731.      ibmail->sender[x]=t;
  732.      pcSource+=2;
  733.      x++;
  734.    }
  735.    ibmail->sender[x]=0;
  736.  
  737.    while(*pcSource<=' ')
  738.      pcSource++;
  739.  
  740.    tmp[2]=0;
  741.    x=0;
  742.    while(*pcSource>' ') {
  743.      tmp[0]=*pcSource;
  744.      tmp[1]=*(pcSource+1);
  745.      sscanf(tmp,"%X",&t);
  746.      ibmail->senderI[x]=t;
  747.      pcSource+=2;
  748.      x++;
  749.    }
  750.    ibmail->senderI[x]=0;
  751.  
  752.    while(*pcSource<=' ')
  753.      pcSource++;
  754.  
  755.    sscanf(pcSource,"%s",&tmp);
  756.    pcSource+=strlen(tmp);
  757.    sscanf(tmp,"%X",&t);
  758.    ibmail->sender_sex=(sex_type)t;
  759.  
  760.    while(*pcSource<=' ')
  761.      pcSource++;
  762.  
  763.    tmp[2]=0;
  764.    x=0;
  765.    while(*pcSource>' ') {
  766.      tmp[0]=*pcSource;
  767.      tmp[1]=*(pcSource+1);
  768.      sscanf(tmp,"%X",&t);
  769.      ibmail->node_s[x]=t;
  770.      pcSource+=2;
  771.      x++;
  772.    }
  773.    ibmail->node_s[x]=0;
  774.  
  775.    while(*pcSource<=' ')
  776.      pcSource++;
  777.  
  778.    tmp[2]=0;
  779.    x=0;
  780.    while(*pcSource>' ') {
  781.      tmp[0]=*pcSource;
  782.      tmp[1]=*(pcSource+1);
  783.      sscanf(tmp,"%X",&t);
  784.      ibmail->node_r[x]=t;
  785.      pcSource+=2;
  786.      x++;
  787.    }
  788.    ibmail->node_r[x]=0;
  789.  
  790.    while(*pcSource<=' ')
  791.      pcSource++;
  792.  
  793.    tmp[2]=0;
  794.    x=0;
  795.    while(*pcSource>' ') {
  796.      tmp[0]=*pcSource;
  797.      tmp[1]=*(pcSource+1);
  798.      sscanf(tmp,"%X",&t);
  799.      ibmail->recver[x]=t;
  800.      pcSource+=2;
  801.      x++;
  802.    }
  803.    ibmail->recver[x]=0;
  804.    while(*pcSource<=' ')
  805.      pcSource++;
  806.  
  807.    tmp[2]=0;
  808.    x=0;
  809.    while(*pcSource>' ') {
  810.      tmp[0]=*pcSource;
  811.      tmp[1]=*(pcSource+1);
  812.      sscanf(tmp,"%X",&t);
  813.      ibmail->recverI[x]=t;
  814.      pcSource+=2;
  815.      x++;
  816.    }
  817.    ibmail->recverI[x]=0;
  818.    while(*pcSource<=' ')
  819.      pcSource++;
  820.  
  821.    sscanf(pcSource,"%s",&tmp);
  822.    pcSource+=strlen(tmp);
  823.    sscanf(tmp,"%X",&t);
  824.    ibmail->quote_length=t;
  825.  
  826.    while(*pcSource<=' ')
  827.      pcSource++;
  828.  
  829.    sscanf(pcSource,"%s",&tmp);
  830.    pcSource+=strlen(tmp);
  831.    sscanf(tmp,"%X",&t);
  832.    ibmail->length=t;
  833.  
  834.    while(*pcSource<=' ')
  835.      pcSource++;
  836.  
  837.    sscanf(pcSource,"%s",&tmp);
  838.    pcSource+=strlen(tmp);
  839.    sscanf(tmp,"%X",&t);
  840.    ibmail->flirt=t;
  841.  
  842.    while(*pcSource<=' ')
  843.      pcSource++;
  844.  
  845.  
  846.    sscanf(pcSource,"%s",&tmp);
  847.    pcSource+=strlen(tmp);
  848.    sscanf(tmp,"%X",&t);
  849.    ibmail->ill=(desease)t;
  850.  
  851.    while(*pcSource<=' ')
  852.      pcSource++;
  853.  
  854.    sscanf(pcSource,"%s",&tmp);
  855.    pcSource+=strlen(tmp);
  856.    sscanf(tmp,"%X",&t);
  857.    ibmail->inf=t;
  858.  
  859.    while(*pcSource<=' ')
  860.      pcSource++;
  861.  
  862.    for(ln=0;ln<(ibmail->length + ibmail->quote_length) && ln<20;ln++) {
  863.      tmp[2]=0;
  864.      x=0;
  865.      while(*pcSource>' ') {
  866.        tmp[0]=*pcSource;
  867.        tmp[1]=*(pcSource+1);
  868.        sscanf(tmp,"%X",&t);
  869.        (ibmail->lines)[ln][x]=t;
  870.        pcSource+=2;
  871.        x++;
  872.        if(x>80) break;
  873.      }
  874.      while(*pcSource<=' ')
  875.        pcSource++;
  876.  
  877.      while(*pcSource>' ') {
  878.        tmp[0]=*pcSource;
  879.        tmp[1]=*(pcSource+1);
  880.        sscanf(tmp,"%X",&t);
  881.        (ibmail->lines)[ln][x]=t;
  882.        pcSource+=2;
  883.        x++;
  884.        if(x>80) break;
  885.      }
  886.  
  887.      while(*pcSource<=' ')
  888.        pcSource++;
  889.  
  890.      while(*pcSource>' ') {
  891.        tmp[0]=*pcSource;
  892.        tmp[1]=*(pcSource+1);
  893.        sscanf(tmp,"%X",&t);
  894.        (ibmail->lines)[ln][x]=t;
  895.        pcSource+=2;
  896.        x++;
  897.        if(x>80) break;
  898.      }
  899.      while(*pcSource<=' ')
  900.        pcSource++;
  901.  
  902.      while(*pcSource>' ') {
  903.        tmp[0]=*pcSource;
  904.        tmp[1]=*(pcSource+1);
  905.        sscanf(tmp,"%X",&t);
  906.        (ibmail->lines)[ln][x]=t;
  907.        pcSource+=2;
  908.        x++;
  909.        if(x>80) break;
  910.      }
  911.      (ibmail->lines)[ln][x]=0;
  912.      while(*pcSource<=' ')
  913.        pcSource++;
  914.    }
  915. }
  916.  
  917.  
  918. int DecodeBufferR(const char *pszSource, void *pDestBuffer)
  919.    {
  920.    const char *pcSource = pszSource;
  921.    char *pcDest = (char *)pDestBuffer;
  922.    char *size[2];
  923.    int iDestLocation;
  924.    int nBufferSize=0;
  925.    tBool bFirstOfByte = TRUE;
  926.  
  927.    /* Search for beginning of buffer delimiter char, returning if not found */
  928.    while(*pcSource && *pcSource != DELIMITER_CHAR) ++pcSource;
  929.    if(!*pcSource) return(0);
  930.  
  931.    /* Move pointer to first char after delimiter char */
  932.    ++pcSource;
  933.  
  934.    /* Loop until destination buffer is full, delimiter char is encountered, */
  935.    /* or end of source buffer is encountered */
  936.    iDestLocation = 0;
  937.    while(iDestLocation < (nBufferSize+2) && *pcSource
  938.     && *pcSource != DELIMITER_CHAR)
  939.       {
  940.       /* If this is a valid data character */
  941.       if(*pcSource >= 0x40 && *pcSource <= 0x7e)
  942.      {
  943.      /* If this is first character of byte */
  944.      if(bFirstOfByte)
  945.         {
  946.         if(iDestLocation<2)
  947.           *size[iDestLocation] = *pcSource & 0x3f;
  948.         else
  949.           *pcDest = *pcSource & 0x3f;
  950.  
  951.         /* Toggle bFirstOfByte */
  952.         bFirstOfByte = FALSE;
  953.         }
  954.      else /* if(!bFirstOfByte) */
  955.         {
  956.         if(iDestLocation<2)
  957.           *size[iDestLocation] |= (*pcSource & 0x30) << 2;
  958.         else
  959.           {
  960.           *pcDest |= (*pcSource & 0x30) << 2;
  961.           ++pcDest;
  962.           }
  963.  
  964.         /* Increment destination */
  965.         ++iDestLocation;
  966.  
  967.         /* Toggle bFirstOfByte */
  968.         bFirstOfByte = TRUE;
  969.         }
  970.      if(iDestLocation==2)
  971.        {
  972.        nBufferSize=*(int *)size;
  973.        pDestBuffer=malloc(nBufferSize);
  974.        }
  975.      }
  976.       /* Increment source byte pointer */
  977.       ++pcSource;
  978.       }
  979.    return(nBufferSize);
  980.    }
  981.  
  982.  
  983.  
  984. DWORD GetNextMSGID(void)
  985.    {
  986.    /* MSGID should be unique for every message, for as long as possible.   */
  987.    /* This technique adds the current time, in seconds since midnight on   */
  988.    /* January 1st, 1970 to a psuedo-random number. The random generator    */
  989.    /* is not seeded, as the application may have already seeded it for its */
  990.    /* own purposes. Even if not seeded, the inclusion of the current time  */
  991.    /* will cause the MSGID to almost always be different.                  */
  992.    return((DWORD)time(NULL) + (DWORD)rand());
  993.    }
  994.  
  995.  
  996. tBool CreateMessage(char *pszMessageDir, tMessageHeader *pHeader,
  997.             char *pszText)
  998.    {
  999.    DWORD lwNewMsgNum;
  1000.  
  1001.    /* Get new message number */
  1002.    lwNewMsgNum = GetFirstUnusedMsgNum(pszMessageDir);
  1003.  
  1004.    /* Use WriteMessage() to create new message */
  1005.    return(WriteMessage(pszMessageDir, lwNewMsgNum, pHeader, pszText));
  1006.    }
  1007.  
  1008.  
  1009. void GetMessageFilename(char *pszMessageDir, DWORD lwMessageNum,
  1010.             char *pszOut)
  1011.    {
  1012.    char szFileName[FILENAME_CHARS + 1];
  1013.  
  1014.    sprintf(szFileName, "%ld.msg", lwMessageNum);
  1015.    MakeFilename(pszMessageDir, szFileName, pszOut);
  1016.    }
  1017.  
  1018.  
  1019. tBool WriteMessage(char *pszMessageDir, DWORD lwMessageNum,
  1020.            tMessageHeader *pHeader, char *pszText)
  1021.    {
  1022.    char szFileName[PATH_CHARS + FILENAME_CHARS + 2];
  1023.    int hFile;
  1024.    size_t nTextSize;
  1025.  
  1026.    /* Get fully qualified filename of message to write */
  1027.    GetMessageFilename(pszMessageDir, lwMessageNum, szFileName);
  1028.  
  1029.    /* Open message file */
  1030.    hFile = open(szFileName, O_WRONLY|O_BINARY|O_CREAT|O_DENYALL,
  1031.                 S_IREAD|S_IWRITE);
  1032.  
  1033.    /* If open failed, return FALSE */
  1034.    if(hFile == -1) return(FALSE);
  1035.  
  1036.    /* Attempt to write header */
  1037.    if(write(hFile, pHeader, sizeof(tMessageHeader)) != sizeof(tMessageHeader))
  1038.       {
  1039.       /* On failure, close file, erase file, and return FALSE */
  1040.       close(hFile);
  1041.       unlink(szFileName);
  1042.       return(FALSE);
  1043.       }
  1044.  
  1045.    /* Determine size of message text, including string terminator */
  1046.    nTextSize = strlen(pszText) + 1;
  1047.  
  1048.    /* Attempt to write message text */
  1049.    if(write(hFile, pszText, nTextSize) != nTextSize)
  1050.       {
  1051.       /* On failure, close file, erase file, and return FALSE */
  1052.       close(hFile);
  1053.       unlink(szFileName);
  1054.       return(FALSE);
  1055.       }
  1056.  
  1057.    /* Close message file */
  1058.    close(hFile);
  1059.  
  1060.    /* Return with success */
  1061.    return(TRUE);
  1062.    }
  1063.  
  1064.  
  1065. tBool ReadMessage(char *pszMessageDir, DWORD lwMessageNum,
  1066.                   tMessageHeader *pHeader, char **ppszText)
  1067.    {
  1068.    char szFileName[PATH_CHARS + FILENAME_CHARS + 2];
  1069.    int hFile;
  1070.    size_t nTextSize;
  1071.  
  1072.    /* Get fully qualified filename of message to read */
  1073.    GetMessageFilename(pszMessageDir, lwMessageNum, szFileName);
  1074.  
  1075.    /* Open message file */
  1076.    hFile = open(szFileName, O_RDONLY|O_BINARY|O_DENYWRITE);
  1077.  
  1078.    /* If open failed, return FALSE */
  1079.    if(hFile == -1) return(FALSE);
  1080.  
  1081.    /* Determine size of message body */
  1082.    nTextSize = (size_t)filelength(hFile) - sizeof(tMessageHeader);
  1083.  
  1084.    /* Attempt to allocate space for message body, plus character for added */
  1085.    /* string terminator.                                                   */
  1086.    if((*ppszText = (char *)malloc(nTextSize + 1)) == NULL)
  1087.       {
  1088.       /* On failure, close file and return FALSE */
  1089.       close(hFile);
  1090.       return(FALSE);
  1091.       }
  1092.  
  1093.    /* Attempt to read header */
  1094.    if(read(hFile, pHeader, sizeof(tMessageHeader)) != sizeof(tMessageHeader))
  1095.       {
  1096.       /* On failure, close file, deallocate message buffer and return FALSE */
  1097.       close(hFile);
  1098.       free(*ppszText);
  1099.       return(FALSE);
  1100.       }
  1101.  
  1102.    /* Attempt to read message text */
  1103.    if(read(hFile, *ppszText, nTextSize) != nTextSize)
  1104.       {
  1105.       /* On failure, close file, deallocate message buffer and return FALSE */
  1106.       close(hFile);
  1107.       free(*ppszText);
  1108.       return(FALSE);
  1109.       }
  1110.  
  1111.    /* Ensure that message buffer is NULL-terminated */
  1112.    (*ppszText)[nTextSize + 1] = '\0';
  1113.  
  1114.    /* Close message file */
  1115.    close(hFile);
  1116.  
  1117.    /* Return with success */
  1118.    return(TRUE);
  1119.    }
  1120.  
  1121.  
  1122. DWORD GetFirstUnusedMsgNum(char *pszMessageDir)
  1123.    {
  1124.    DWORD lwHighestMsgNum = 0;
  1125.    DWORD lwCurrentMsgNum;
  1126.    struct ffblk DirEntry;
  1127.    char szFileName[PATH_CHARS + FILENAME_CHARS + 2];
  1128.  
  1129.    MakeFilename(pszMessageDir, "*.msg", szFileName);
  1130.  
  1131.    if(findfirst(szFileName, &DirEntry, FA_ARCH) == 0)
  1132.       {
  1133.       do
  1134.      {
  1135.      lwCurrentMsgNum = atol(DirEntry.ff_name);
  1136.      if(lwCurrentMsgNum > lwHighestMsgNum)
  1137.         {
  1138.         lwHighestMsgNum = lwCurrentMsgNum;
  1139.         }
  1140.      } while(findnext(&DirEntry) == 0);
  1141.       }
  1142.  
  1143.    return(lwHighestMsgNum + 1);
  1144.    }
  1145.  
  1146.  
  1147. tIBResult ValidateInfoStruct(tIBInfo *pInfo)
  1148.    {
  1149.    if(pInfo == NULL) return(eBadParameter);
  1150.  
  1151.    if(!DirExists(pInfo->szNetmailDir)) return(eMissingDir);
  1152.  
  1153.    od_printf("E");
  1154.    od_get_answer("1");
  1155.  
  1156.    if(strlen(pInfo->szProgName) == 0) return(eBadParameter);
  1157.  
  1158.    od_printf("F");
  1159.    od_get_answer("1");
  1160.  
  1161.  
  1162.    return(eSuccess);
  1163.    }
  1164.  
  1165.  
  1166. tIBResult IBGet(tIBInfo *pInfo, void *pBuffer, int nMaxBufferSize)
  1167.    {
  1168.    tIBResult ToReturn;
  1169.    struct ffblk DirEntry;
  1170.    DWORD lwCurrentMsgNum;
  1171.    tMessageHeader MessageHeader;
  1172.    char szFileName[PATH_CHARS + FILENAME_CHARS + 2];
  1173.    char *pszText;
  1174.    tFidoNode ThisNode,OtherNode;
  1175.  
  1176.    /* Validate information structure */
  1177.    ToReturn = ValidateInfoStruct(pInfo);
  1178.    if(ToReturn != eSuccess) return(ToReturn);
  1179.  
  1180.    /* Get this node's address from string */
  1181.    ConvertStringToAddress(&ThisNode, pInfo->szThisNodeAddress);
  1182.  
  1183.    MakeFilename(pInfo->szNetmailDir, "*.msg", szFileName);
  1184.  
  1185.    /* Seach through each message file in the netmail directory, in no */
  1186.    /* particular order.                                               */
  1187.    if(findfirst(szFileName, &DirEntry, FA_ARCH) == 0)
  1188.       {
  1189.       do
  1190.      {
  1191.      lwCurrentMsgNum = atol(DirEntry.ff_name);
  1192.  
  1193.      /* If able to read message */
  1194.      if(ReadMessage(pInfo->szNetmailDir, lwCurrentMsgNum, &MessageHeader,
  1195.         &pszText))
  1196.         {
  1197. /*        od_printf("\n\rREAD THROUGH MESSAGE\n\r");
  1198.         od_printf("|%s|\n\r",MessageHeader.szToUserName);
  1199.         od_printf("|%s|\n\r",pInfo->szProgName);
  1200.         od_printf("%d:",MessageHeader.wDestZone);
  1201.         od_printf("%d/",MessageHeader.wDestNet);
  1202.         od_printf("%d.",MessageHeader.wDestNode);
  1203.         od_printf("%d\n\r",MessageHeader.wDestPoint);
  1204.  
  1205.         od_get_answer("1");*/
  1206.         /* If message is for us, and hasn't be read yet */
  1207.         ConvertStringToAddress(&OtherNode,&MessageHeader.szToUserName[3]);
  1208.  
  1209.         if(strcmp(MessageHeader.szFromUserName, pInfo->szProgName) == 0
  1210.            && (ThisNode.wZone == OtherNode.wZone || OtherNode.wZone==0 || ThisNode.wZone==0)
  1211.            && ThisNode.wNet == OtherNode.wNet
  1212.            && ThisNode.wNode == OtherNode.wNode
  1213.            && ThisNode.wPoint == OtherNode.wPoint
  1214.            && !(MessageHeader.wAttribute & ATTRIB_RECEIVED))
  1215.            {
  1216.  
  1217. /*           od_printf("\n\rUNREAD AND FOR US\n\r");
  1218.            od_get_answer("1");*/
  1219.  
  1220.            /* Decode message text, placing information in buffer */
  1221.            DecodeBuffer(pszText, pBuffer, nMaxBufferSize);
  1222.  
  1223.            /* If received messages should be deleted */
  1224.            if(pInfo->bEraseOnReceive)
  1225.           {
  1226.           /* Determine filename of message to erase */
  1227.           GetMessageFilename(pInfo->szNetmailDir, lwCurrentMsgNum,
  1228.                      szFileName);
  1229.  
  1230.           /* Attempt to erase file */
  1231.           if(unlink(szFileName) == -1)
  1232.              {
  1233.              ToReturn = eGeneralFailure;
  1234.              }
  1235.           else
  1236.              {
  1237.              ToReturn = eSuccess;
  1238.              }
  1239.           }
  1240.  
  1241.            /* If received messages should not be deleted */
  1242.            else /* if(!pInfo->bEraseOnReceive) */
  1243.           {
  1244.           /* Mark message as read */
  1245.           MessageHeader.wAttribute |= ATTRIB_RECEIVED;
  1246.           ++MessageHeader.wTimesRead;
  1247.  
  1248.           /* Attempt to rewrite message */
  1249.           if(!WriteMessage(pInfo->szNetmailDir, lwCurrentMsgNum,
  1250.            &MessageHeader, pszText))
  1251.              {
  1252.              ToReturn = eGeneralFailure;
  1253.              }
  1254.           else
  1255.              {
  1256.              ToReturn = eSuccess;
  1257.              }
  1258.           }
  1259.  
  1260.            /* Deallocate message text buffer */
  1261.            free(pszText);
  1262.  
  1263.            /* Return appropriate value */
  1264.            return(ToReturn);
  1265.            }
  1266.         free(pszText);
  1267.         }
  1268.      } while(findnext(&DirEntry) == 0);
  1269.       }
  1270.  
  1271.    /* If no new messages were found */
  1272.    return(eNoMoreMessages);
  1273.    }
  1274.  
  1275. tIBResult IBGetMail(tIBInfo *pInfo, ibbs_mail_type *ibmail)
  1276.    {
  1277.    tIBResult ToReturn;
  1278.    struct ffblk DirEntry;
  1279.    DWORD lwCurrentMsgNum;
  1280.    tMessageHeader MessageHeader;
  1281.    char szFileName[PATH_CHARS + FILENAME_CHARS + 2];
  1282.    char *pszText;
  1283.    tFidoNode ThisNode,OtherNode;
  1284.  
  1285.    /* Validate information structure */
  1286.    ToReturn = ValidateInfoStruct(pInfo);
  1287.    if(ToReturn != eSuccess) return(ToReturn);
  1288.  
  1289.    /* Get this node's address from string */
  1290.    ConvertStringToAddress(&ThisNode, pInfo->szThisNodeAddress);
  1291.  
  1292.    MakeFilename(pInfo->szNetmailDir, "*.msg", szFileName);
  1293.  
  1294.    /* Seach through each message file in the netmail directory, in no */
  1295.    /* particular order.                                               */
  1296.    if(findfirst(szFileName, &DirEntry, FA_ARCH) == 0)
  1297.       {
  1298.       do
  1299.      {
  1300.      lwCurrentMsgNum = atol(DirEntry.ff_name);
  1301.  
  1302.      /* If able to read message */
  1303.      if(ReadMessage(pInfo->szNetmailDir, lwCurrentMsgNum, &MessageHeader,
  1304.         &pszText))
  1305.         {
  1306.         /* If message is for us, and hasn't be read yet */
  1307.         ConvertStringToAddress(&OtherNode,&MessageHeader.szToUserName[3]);
  1308.  
  1309.         if(strcmp(MessageHeader.szFromUserName, pInfo->szProgName) == 0
  1310.            && (ThisNode.wZone == OtherNode.wZone || OtherNode.wZone==0 || ThisNode.wZone==0)
  1311.            && ThisNode.wNet == OtherNode.wNet
  1312.            && ThisNode.wNode == OtherNode.wNode
  1313.            && ThisNode.wPoint == OtherNode.wPoint
  1314.            && !(MessageHeader.wAttribute & ATTRIB_RECEIVED))
  1315.            {
  1316.            /* Decode message text, placing information in buffer */
  1317.            DecodeMail(pszText, ibmail);
  1318.  
  1319.            /* If received messages should be deleted */
  1320.            if(pInfo->bEraseOnReceive)
  1321.           {
  1322.           /* Determine filename of message to erase */
  1323.           GetMessageFilename(pInfo->szNetmailDir, lwCurrentMsgNum,
  1324.                      szFileName);
  1325.  
  1326.           /* Attempt to erase file */
  1327.           if(unlink(szFileName) == -1)
  1328.              {
  1329.              ToReturn = eGeneralFailure;
  1330.              }
  1331.           else
  1332.              {
  1333.              ToReturn = eSuccess;
  1334.              }
  1335.           }
  1336.  
  1337.            /* If received messages should not be deleted */
  1338.            else /* if(!pInfo->bEraseOnReceive) */
  1339.           {
  1340.           /* Mark message as read */
  1341.           MessageHeader.wAttribute |= ATTRIB_RECEIVED;
  1342.           ++MessageHeader.wTimesRead;
  1343.  
  1344.           /* Attempt to rewrite message */
  1345.           if(!WriteMessage(pInfo->szNetmailDir, lwCurrentMsgNum,
  1346.            &MessageHeader, pszText))
  1347.              {
  1348.              ToReturn = eGeneralFailure;
  1349.              }
  1350.           else
  1351.              {
  1352.              ToReturn = eSuccess;
  1353.              }
  1354.           }
  1355.  
  1356.            /* Deallocate message text buffer */
  1357.            free(pszText);
  1358.  
  1359.            /* Return appropriate value */
  1360.            return(ToReturn);
  1361.            }
  1362.         free(pszText);
  1363.         }
  1364.      } while(findnext(&DirEntry) == 0);
  1365.       }
  1366.  
  1367.    /* If no new messages were found */
  1368.    return(eNoMoreMessages);
  1369.    }
  1370.  
  1371.  
  1372. tIBResult IBGetR(tIBInfo *pInfo, void *pBuffer, int *nBufferLen)
  1373.    {
  1374.    tIBResult ToReturn;
  1375.    struct ffblk DirEntry;
  1376.    DWORD lwCurrentMsgNum;
  1377.    tMessageHeader MessageHeader;
  1378.    char szFileName[PATH_CHARS + FILENAME_CHARS + 2];
  1379.    char *pszText;
  1380.    tFidoNode ThisNode,OtherNode;
  1381.  
  1382.    /* Validate information structure */
  1383.    ToReturn = ValidateInfoStruct(pInfo);
  1384.    if(ToReturn != eSuccess) return(ToReturn);
  1385.  
  1386.    /* Get this node's address from string */
  1387.    ConvertStringToAddress(&ThisNode, pInfo->szThisNodeAddress);
  1388.  
  1389.    MakeFilename(pInfo->szNetmailDir, "*.msg", szFileName);
  1390.  
  1391.    /* Seach through each message file in the netmail directory, in no */
  1392.    /* particular order.                                               */
  1393.    if(findfirst(szFileName, &DirEntry, FA_ARCH) == 0)
  1394.       {
  1395.       do
  1396.          {
  1397.      lwCurrentMsgNum = atol(DirEntry.ff_name);
  1398.  
  1399.          /* If able to read message */
  1400.          if(ReadMessage(pInfo->szNetmailDir, lwCurrentMsgNum, &MessageHeader,
  1401.             &pszText))
  1402.         {
  1403.         ConvertStringToAddress(&OtherNode,&MessageHeader.szToUserName[3]);
  1404.  
  1405.         if(strcmp(MessageHeader.szFromUserName, pInfo->szProgName) == 0
  1406.            && (ThisNode.wZone == OtherNode.wZone || OtherNode.wZone==0 || ThisNode.wZone==0)
  1407.            && ThisNode.wNet == OtherNode.wNet
  1408.            && ThisNode.wNode == OtherNode.wNode
  1409.            && ThisNode.wPoint == OtherNode.wPoint
  1410.            && !(MessageHeader.wAttribute & ATTRIB_RECEIVED))
  1411.            {
  1412.            /* Decode message text, placing information in buffer */
  1413.            *nBufferLen=DecodeBufferR(pszText, pBuffer);
  1414.  
  1415.                /* If received messages should be deleted */
  1416.            if(pInfo->bEraseOnReceive)
  1417.                   {
  1418.                   /* Determine filename of message to erase */
  1419.                   GetMessageFilename(pInfo->szNetmailDir, lwCurrentMsgNum,
  1420.                                      szFileName);
  1421.  
  1422.                   /* Attempt to erase file */
  1423.           if(unlink(szFileName) == -1)
  1424.                      {
  1425.                      ToReturn = eGeneralFailure;
  1426.                      }
  1427.                   else
  1428.                      {
  1429.                      ToReturn = eSuccess;
  1430.                      }
  1431.                   }
  1432.  
  1433.            /* If received messages should not be deleted */
  1434.                else /* if(!pInfo->bEraseOnReceive) */
  1435.                   {
  1436.                   /* Mark message as read */
  1437.                   MessageHeader.wAttribute |= ATTRIB_RECEIVED;
  1438.                   ++MessageHeader.wTimesRead;
  1439.  
  1440.                   /* Attempt to rewrite message */
  1441.                   if(!WriteMessage(pInfo->szNetmailDir, lwCurrentMsgNum,
  1442.                    &MessageHeader, pszText))
  1443.              {
  1444.                      ToReturn = eGeneralFailure;
  1445.                      }
  1446.                   else
  1447.                      {
  1448.                      ToReturn = eSuccess;
  1449.                      }
  1450.                   }
  1451.  
  1452.                /* Deallocate message text buffer */
  1453.            free(pszText);
  1454.  
  1455.                /* Return appropriate value */
  1456.                return(ToReturn);
  1457.                }
  1458.             free(pszText);
  1459.             }
  1460.          } while(findnext(&DirEntry) == 0);
  1461.       }
  1462.  
  1463.    /* If no new messages were found */
  1464.    return(eNoMoreMessages);
  1465.    }
  1466.  
  1467.  
  1468. void
  1469. ConvertAddressToString(char *pszDest, const tFidoNode *pNode)
  1470. {
  1471.   if(pNode->wZone == 0) {
  1472.     if(pNode->wPoint == 0) {
  1473.       sprintf(pszDest, "%u/%u", pNode->wNet, pNode->wNode);
  1474.     } else {
  1475.       sprintf(pszDest, "%u/%u.%u", pNode->wNet, pNode->wNode,pNode->wPoint);
  1476.     }
  1477.   } else {
  1478.     if(pNode->wPoint == 0) {
  1479.       sprintf(pszDest, "%u:%u/%u", pNode->wZone, pNode->wNet, pNode->wNode);
  1480.     } else {
  1481.       sprintf(pszDest, "%u:%u/%u.%u", pNode->wZone, pNode->wNet, pNode->wNode,pNode->wPoint);
  1482.     }
  1483.   }
  1484. }
  1485.  
  1486.  
  1487. void
  1488. ConvertStringToAddress(tFidoNode *pNode, const char *pszSource)
  1489. {
  1490.   pNode->wZone = 0;
  1491.   pNode->wNet = 0;
  1492.   pNode->wNode = 0;
  1493.   pNode->wPoint = 0;
  1494.   if(strchr(pszSource,':')==NULL) {
  1495.     sscanf(pszSource, "%u/%u.%u", &(pNode->wNet),&(pNode->wNode), &(pNode->wPoint));
  1496.   } else {
  1497.     sscanf(pszSource, "%u:%u/%u.%u", &(pNode->wZone), &(pNode->wNet),&(pNode->wNode), &(pNode->wPoint));
  1498.   }
  1499. }
  1500.  
  1501.  
  1502. #define NUM_KEYWORDS       10
  1503.  
  1504. #define KEYWORD_ADDRESS    0
  1505. #define KEYWORD_USER_NAME  1
  1506. #define KEYWORD_MAIL_DIR   2
  1507. #define KEYWORD_CRASH      3
  1508. #define KEYWORD_HOLD       4
  1509. #define KEYWORD_KILL_SENT  5
  1510. #define KEYWORD_KILL_RCVD  6
  1511. #define KEYWORD_LINK_WITH  7
  1512. #define KEYWORD_LINK_NAME  8
  1513. #define KEYWORD_LINK_LOC   9
  1514.  
  1515. char *apszKeyWord[NUM_KEYWORDS] = {"SystemAddress",
  1516.                                    "UserName",
  1517.                                    "NetmailDir",
  1518.                                    "Crash",
  1519.                    "Hold",
  1520.                    "EraseOnSend",
  1521.                    "EraseOnReceive",
  1522.                    "LinkWith",
  1523.                    "LinkName",
  1524.                    "LinkLocation"};
  1525.  
  1526. tIBResult IBReadConfig(tIBInfo *pInfo, char *pszConfigFile)
  1527.    {
  1528.    /* Set default values for pInfo settings */
  1529. /*   pInfo->nTotalSystems = 0;
  1530.    pInfo->paOtherSystem = NULL;*/
  1531.  
  1532.    /* Process configuration file */
  1533.    if(!ProcessConfigFile(pszConfigFile, NUM_KEYWORDS, apszKeyWord,
  1534.              ProcessConfigLine, (void *)pInfo))
  1535.       {
  1536.       return(eFileOpenError);
  1537.       }
  1538.  
  1539.    /* else */
  1540.    return(eSuccess);
  1541.    }
  1542.  
  1543.  
  1544. void ProcessConfigLine(int nKeyword, char *pszParameter, void *pCallbackData)
  1545.    {
  1546.    tIBInfo *pInfo = (tIBInfo *)pCallbackData;
  1547.    tOtherNode *paNewNodeArray;
  1548.  
  1549.    switch(nKeyword)
  1550.       {
  1551.       case KEYWORD_ADDRESS:
  1552.          strncpy(pInfo->szThisNodeAddress, pszParameter, NODE_ADDRESS_CHARS);
  1553.          pInfo->szThisNodeAddress[NODE_ADDRESS_CHARS] = '\0';
  1554.      break;
  1555.  
  1556.       case KEYWORD_USER_NAME:
  1557.          strncpy(pInfo->szProgName, pszParameter, PROG_NAME_CHARS);
  1558.          pInfo->szProgName[PROG_NAME_CHARS] = '\0';
  1559.          break;
  1560.  
  1561.       case KEYWORD_MAIL_DIR:
  1562.          strncpy(pInfo->szNetmailDir, pszParameter, PATH_CHARS);
  1563.          pInfo->szNetmailDir[PATH_CHARS] = '\0';
  1564.      break;
  1565.  
  1566.       case KEYWORD_CRASH:
  1567.          if(stricmp(pszParameter, "Yes") == 0)
  1568.             {
  1569.             pInfo->bCrash = TRUE;
  1570.             }
  1571.          else if(stricmp(pszParameter, "No") == 0)
  1572.             {
  1573.             pInfo->bCrash = FALSE;
  1574.         }
  1575.          break;
  1576.  
  1577.       case KEYWORD_HOLD:
  1578.          if(stricmp(pszParameter, "Yes") == 0)
  1579.             {
  1580.             pInfo->bHold = TRUE;
  1581.             }
  1582.          else if(stricmp(pszParameter, "No") == 0)
  1583.             {
  1584.         pInfo->bHold = FALSE;
  1585.             }
  1586.      break;
  1587.  
  1588.       case KEYWORD_KILL_SENT:
  1589.          if(stricmp(pszParameter, "Yes") == 0)
  1590.             {
  1591.             pInfo->bEraseOnSend = TRUE;
  1592.             }
  1593.          else if(stricmp(pszParameter, "No") == 0)
  1594.         {
  1595.             pInfo->bEraseOnSend = FALSE;
  1596.         }
  1597.          break;
  1598.  
  1599.       case KEYWORD_KILL_RCVD:
  1600.          if(stricmp(pszParameter, "Yes") == 0)
  1601.             {
  1602.             pInfo->bEraseOnReceive = TRUE;
  1603.             }
  1604.      else if(stricmp(pszParameter, "No") == 0)
  1605.             {
  1606.         pInfo->bEraseOnReceive = FALSE;
  1607.             }
  1608.          break;
  1609.  
  1610.       case KEYWORD_LINK_WITH:
  1611.          if(pInfo->nTotalSystems == 0)
  1612.             {
  1613.         pInfo->paOtherSystem = (tOtherNode *)malloc(sizeof(tOtherNode));
  1614.         if(pInfo->paOtherSystem == NULL)
  1615.                {
  1616.            break;
  1617.                }
  1618.             }
  1619.          else
  1620.             {
  1621.         if((paNewNodeArray = (tOtherNode *)malloc(sizeof(tOtherNode) *
  1622.              (pInfo->nTotalSystems + 1))) == NULL)
  1623.                {
  1624.            break;
  1625.                }
  1626.  
  1627.             memcpy(paNewNodeArray, pInfo->paOtherSystem, sizeof(tOtherNode) *
  1628.                pInfo->nTotalSystems);
  1629.  
  1630.             free(pInfo->paOtherSystem);
  1631.  
  1632.             pInfo->paOtherSystem = paNewNodeArray;
  1633.             }
  1634.  
  1635.          strncpy(pInfo->paOtherSystem[pInfo->nTotalSystems].szAddress,
  1636.          pszParameter, NODE_ADDRESS_CHARS);
  1637.          pInfo->paOtherSystem[pInfo->nTotalSystems].
  1638.             szAddress[NODE_ADDRESS_CHARS] = '\0';
  1639.          ++pInfo->nTotalSystems;
  1640.          break;
  1641.  
  1642.       case KEYWORD_LINK_NAME:
  1643.          if(pInfo->nTotalSystems != 0)
  1644.         {
  1645.             strncpy(pInfo->paOtherSystem[pInfo->nTotalSystems - 1].szSystemName,
  1646.             pszParameter, SYSTEM_NAME_CHARS);
  1647.             pInfo->paOtherSystem[pInfo->nTotalSystems - 1].
  1648.                szSystemName[SYSTEM_NAME_CHARS] = '\0';
  1649.             }
  1650.          break;
  1651.  
  1652.       case KEYWORD_LINK_LOC:
  1653.          if(pInfo->nTotalSystems != 0)
  1654.         {
  1655.             strncpy(pInfo->paOtherSystem[pInfo->nTotalSystems - 1].szLocation,
  1656.             pszParameter, LOCATION_CHARS);
  1657.             pInfo->paOtherSystem[pInfo->nTotalSystems - 1].
  1658.                szLocation[LOCATION_CHARS] = '\0';
  1659.             }
  1660.          break;
  1661.       }
  1662.    }
  1663.  
  1664.  
  1665. /* Configuration file reader settings */
  1666. #define CONFIG_LINE_SIZE 128
  1667. #define MAX_TOKEN_CHARS 32
  1668.  
  1669. tBool ProcessConfigFile(char *pszFileName, int nKeyWords, char **papszKeyWord,
  1670.                   void (*pfCallBack)(int, char *, void *), void *pCallBackData)
  1671.    {
  1672.    FILE *pfConfigFile;
  1673.    char szConfigLine[CONFIG_LINE_SIZE + 1];
  1674.    char *pcCurrentPos;
  1675.    unsigned int uCount;
  1676.    char szToken[MAX_TOKEN_CHARS + 1];
  1677.    int iKeyWord;
  1678.  
  1679.    /* Attempt to open configuration file */
  1680.    if((pfConfigFile = fopen(pszFileName, "rt")) == NULL)
  1681.       {
  1682.       return(FALSE);
  1683.       }
  1684.  
  1685.    /* While not at end of file */
  1686.    while(!feof(pfConfigFile))
  1687.       {
  1688.       /* Get the next line */
  1689.       if(fgets(szConfigLine, CONFIG_LINE_SIZE + 1 ,pfConfigFile) == NULL) break;
  1690.  
  1691.       /* Ignore all of line after comments or CR/LF char */
  1692.       pcCurrentPos=(char *)szConfigLine;
  1693.       while(*pcCurrentPos)
  1694.      {
  1695.          if(*pcCurrentPos=='\n' || *pcCurrentPos=='\r' || *pcCurrentPos==';')
  1696.         {
  1697.             *pcCurrentPos='\0';
  1698.             break;
  1699.             }
  1700.          ++pcCurrentPos;
  1701.          }
  1702.  
  1703.       /* Search for beginning of first token on line */
  1704.       pcCurrentPos=(char *)szConfigLine;
  1705.       while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
  1706.  
  1707.       /* If no token was found, proceed to process the next line */
  1708.       if(!*pcCurrentPos) continue;
  1709.  
  1710.       /* Get first token from line */
  1711.       uCount=0;
  1712.       while(*pcCurrentPos && !isspace(*pcCurrentPos))
  1713.          {
  1714.      if(uCount<MAX_TOKEN_CHARS) szToken[uCount++]=*pcCurrentPos;
  1715.          ++pcCurrentPos;
  1716.      }
  1717.       if(uCount<=MAX_TOKEN_CHARS)
  1718.          szToken[uCount]='\0';
  1719.       else
  1720.          szToken[MAX_TOKEN_CHARS]='\0';
  1721.  
  1722.       /* Find beginning of configuration option parameters */
  1723.       while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
  1724.  
  1725.        /* Trim trailing spaces from setting string */
  1726.       for(uCount=strlen(pcCurrentPos)-1;uCount>0;--uCount)
  1727.          {
  1728.          if(isspace(pcCurrentPos[uCount]))
  1729.             {
  1730.             pcCurrentPos[uCount]='\0';
  1731.             }
  1732.          else
  1733.             {
  1734.         break;
  1735.             }
  1736.      }
  1737.  
  1738.       /* Loop through list of keywords */
  1739.       for(iKeyWord = 0; iKeyWord < nKeyWords; ++iKeyWord)
  1740.          {
  1741.          /* If keyword matches */
  1742.          if(stricmp(szToken, papszKeyWord[iKeyWord]) == 0)
  1743.             {
  1744.         /* Call keyword processing callback function */
  1745.             (*pfCallBack)(iKeyWord, pcCurrentPos, pCallBackData);
  1746.         }
  1747.          }
  1748.       }
  1749.  
  1750.    /* Close the configuration file */
  1751.    fclose(pfConfigFile);
  1752.  
  1753.    /* Return with success */
  1754.    return(TRUE);
  1755.    }
  1756.